package org.nanhill.gecko;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class HTMLParser {
	private static final Log logger = LogFactory.getLog(HTMLParser.class);

	private SpiderConfig config;

	public HTMLParser(SpiderConfig config) {
		this.config = config;
	}

	public List parseLinksInDocument(URL sourceURL, String textContent) {
		return parseAsHTML(sourceURL, textContent);
	}

	private List parseAsHTML(URL sourceURL, String textContent) {
		logger.debug("parseAsHTML()");
		ArrayList<URL> newURLs = new ArrayList<URL>();
		HashSet<URL> newURLSet = new HashSet<URL>();

		extractAttributesFromTags("img", "src", sourceURL, newURLs, newURLSet,
				textContent);
		extractAttributesFromTags("a", "href", sourceURL, newURLs, newURLSet,
				textContent);
		extractAttributesFromTags("body", "background", sourceURL, newURLs,
				newURLSet, textContent);
		extractAttributesFromTags("frame", "src", sourceURL, newURLs,
				newURLSet, textContent);
		extractAttributesFromTags("IMG", "SRC", sourceURL, newURLs, newURLSet,
				textContent);
		extractAttributesFromTags("A", "HREF", sourceURL, newURLs, newURLSet,
				textContent);
		extractAttributesFromTags("BODY", "BACKGROUND", sourceURL, newURLs,
				newURLSet, textContent);
		extractAttributesFromTags("FRAME", "SRC", sourceURL, newURLs,
				newURLSet, textContent);

		if (newURLs.size() == 0) {
			logger.debug("Got 0 new URLs from HTML parse, check HTML\n"
					+ textContent);
		}
		logger.debug("Returning " + newURLs.size()
				+ " urls extracted from page");
		return newURLs;
	}

	private void extractAttributesFromTags(String tag, String attr,
			URL sourceURL, List<URL> newURLs, Set<URL> newURLSet, String input) {
		logger.debug("extractAttributesFromTags(" + tag + ", " + attr
				+ ", ...)");

		int startPos = 0;
		String startTag = "<" + tag + " ";
		String attrStr = attr + "=\"";
		while (true) {
			int tagPos = input.indexOf(startTag, startPos);
			if (tagPos < 0) {
				return;
			}
			int attrPos = input.indexOf(attrStr, tagPos + 1);
			if (attrPos < 0) {
				startPos = tagPos + 1;
				continue;
			}
			int nextClosePos = input.indexOf(">", tagPos + 1);
			if (attrPos < nextClosePos) {
				// Ooh, found one
				int closeQuotePos = input.indexOf("\"", attrPos
						+ attrStr.length() + 1);
				if (closeQuotePos > 0) {
					String urlStr = input.substring(attrPos + attrStr.length(),
							closeQuotePos);
					if (urlStr.indexOf('#') != -1) {
						urlStr = urlStr.substring(0, urlStr.indexOf('#'));
					}
					// _logClass.debug("Found possible URL string: " + URL);

					if (isMailTo(urlStr)) {
						logMailURL(urlStr);
					} else {
						try {

							URL u = new URL(sourceURL, urlStr);
							if (newURLSet.contains(u)) {
								// _logClass.debug("Already found URL on page: "
								// + u);
							} else {
								newURLs.add(u);
								newURLSet.add(u);
								// _logClass.debug("Found new URL on page: " +
								// u);
							}
						} catch (MalformedURLException murle) {
						}
					}
				}
				startPos = tagPos + 1;
				continue;
			} else {
				startPos = tagPos + 1;
				continue;
			}
		}
	}

	private void logMailURL(String url) {
		logger.debug("logMailURL()");

		try {
			FileWriter appendedFile = new FileWriter(config.getMailtoLogFile()
					.toString(), true);
			PrintWriter pW = new PrintWriter(appendedFile);
			pW.println(url);
			pW.flush();
			pW.close();
		} catch (IOException ioe) {
			logger.warn("Caught IO exception writing mailto URL:"
					+ ioe.getMessage(), ioe);
		}
	}

	/**
	 * Check if a particular URL looks like it's a mailto: style link.
	 */
	private boolean isMailTo(String url) {
		if (url == null) {
			return false;
		}

		url = url.toUpperCase();
		return (url.indexOf("MAILTO:") != -1);
	}
}
